In [13]:
a = "hello"
a
Out[13]:
In [14]:
a = 3
a
Out[14]:
Aunque también es posible difinir una variable usando un tipo concreto no es muy habitual verlo en código de producción.
In [15]:
a = str()
a
Out[15]:
IMPORTANTE: Elegir nombres descriptivos para las variables es crítico. En este documento se utilizan a veces nombres de variables sin significado porque son ejemplos muy simples (sin relación con un problema concreto). En un programa real deben utilizarse siempre conceptos del dominio de la aplicación. (http://www.itiseezee.com/?p=83)
In [16]:
num = 42
num
Out[16]:
En el caso de Python, el entero tiene una peculiaridad: no tiene límite, puede ser arbitrariamente largo.
In [17]:
big_number = 100 ** 100
big_number
Out[17]:
Efectivamente, el operador
In [18]:
a = 32 + 16
a
Out[18]:
In [19]:
3.2//2
Out[19]:
In [20]:
a | 4
Out[20]:
In [21]:
a & 31
Out[21]:
In [22]:
a >> 2
Out[22]:
A pesar de las apariencias, el listado anterior es una serie de invocaciones a métodos, porque como se ha dicho, los enteros también son objetos:
In [23]:
a = 3
a.__add__(4)
Out[23]:
Esto es porque Python permite realizar sobrecarga de operadores, es decir, el lenguaje permite crear tipos (clases) que definen el significado de los operadores. Esto se realiza por medio de métodos especiales (como el __add__ del listado anterior). Volveremos con este tema más adelante.
El otro tipo de dato numérico esencial es el flotante (float). Como en el caso del entero, el float de Python tiene precisión y tamaño arbitrário, lo cual simplifica mucho las cosas cuando se requieren número muy grandes. Para definir una variable de tipo float, basta como siempre, asignar un literal:
In [24]:
size = 3.4
size
Out[24]:
Los operadores de Python hacen promoción automática de tipos cuando se operan por ejemplo enteros con flotantes:
In [25]:
4 * 4.2
Out[25]:
Eso no significa que esté permitido aplicar cualquier operador a cualquier pareja de operandos. Python a pesar de ser dinámico es un lenguaje fuertemente tipado:
In [26]:
"hello" + 3.2
Aunque el operador de suma está de hecho definido para las cadenas su significado es la concatenación como se puede ver en el mensaje de error.
In [ ]:
n = 3 + 4j
n * 2
In [ ]:
n.imag
In [ ]:
abs(n)
In [ ]:
type(n)
In [ ]:
1j * 1j
In [ ]:
b1 = True
Soporta los operadores clásicos: and, or y not:
In [ ]:
not b1
In [ ]:
b1 and False
In [ ]:
b1 or False
Como ocurre en C, cualquier expresión genera (o puede convertirse) a un valor lógico, lo que resulta muy útil y permite simplificar el código en muchos casos:
In [ ]:
3 > 5
In [ ]:
bool(3.7)
El 0 (entero, flotante o complejo) se evalúa como falso. Las secuencias vacías, incluidas las cadenas también se consideran False.
In [27]:
bool("")
Out[27]:
Las operaciones and y or tienen un tratamiento interesante de sus operandos. La operación and realmente no devuelve un booleano. Es su lugar devuelve el primer operando que se evalúe como falso, y los demás no llegan a ejecutarse nunca:
In [30]:
4 and (2 -2) and (5 - 3)
Out[30]:
El 0 que devuelve la sentencia es el resultado de la operación 2 - 2, y la operación 5 - 3 no se ha ejecutado. La operación or realiza algo similar. Devuelve el primer valor que se evalúe como cierto, y no evalúa ningún operando más.
In [31]:
2 > 3 or 2 + 3 or 3 - 1
Out[31]:
Python evalúa 2 > 3 (que es falso), después evalúa 2 + 3, y como es cierto (distinto de cero), lo devuelve sin ejecutar nada más.
In [32]:
a = "example"
a = None
bool(a)
Out[32]:
In [33]:
2 + 3 * 4
Out[33]:
Para modificar las reglas de precedencia se pueden utilizar paréntesis:
In [34]:
(2 + 3) * 4
Out[34]:
Como se puede comprobar, la multiplicación tiene prioridad sobre la suma. En concreto, las reglas para los operadores matemáticos son:
Operador | Significado |
---|---|
\*\* | potencia |
+ y - (un operando) | signo del valor |
\*, / y % (dos operandos) | multiplicación, división y módulo |
+ y - (dos operandos) | suma y resta |
En caso de la más mínima duda, mejor poner paréntesis.
Las contenedores de Python son aquellos tipos de datos que permiten grupos valores. Todos permiten almacenar valores de tipos diferentes en el mismo contenedor de forma directa. Todos los contenedores son indexables, y eso es mucho decir en el caso de Python. En este momento se muestran los más sencillos: cadenas, listas, tuplas, diccionarios y conjuntos.
Desde el punto de vista lógico, todas los contenedores se evalúan como falso cuando están vacíos.
In [35]:
what = "Hello"
who = 'World'
what + ' ' + who
Out[35]:
Como se puede apreciar en ese ejemplo, soportan el operador de concatenación. También el de multiplicación (siempre que sea con un entero):
In [36]:
"hello " * 3
Out[36]:
In [37]:
what[0]
Out[37]:
Como en muchos lenguajes, el primer elemento corresponde con el índice 0. Pero también permite indexar desde el final si el indice es negativo (realmente muy útil!).
In [42]:
what[-1]
Out[42]:
Algo no tan común es el slicing, que permite indicar un rango mediante dos índices separados por ':':
In [43]:
who[1:4]
Out[43]:
In [44]:
who[-4:-1]
Out[44]:
Además, los indices son opcionales si corresponden con el principio y final respectivamente.
In [45]:
who[:4]
Out[45]:
In [ ]:
who[2:]
Un tercer índice permite además indicar un "paso", es decir, la cantidad de elementos que debe saltar. Y ese paso puede ser negativo.
In [46]:
(what + who)[2:9:2]
Out[46]:
In [47]:
(what + who)[::-1]
Out[47]:
Las cadenas son tipos inmutables, es decir, no se puede modificar su valor:
In [48]:
who[2] = "K"
In [49]:
t1 = (1, "a", 3.2)
Son indexables igual que las cadenas y soportan los mismo operadores de slicing, y también son inmutables.
In [50]:
t1[1]
Out[50]:
Se pueden crear a partir de varias variables independientes (empaquetar):
In [51]:
text = "hi"
num = 42
t2 = text, num
t2
Out[51]:
Y también obtener los valores por separado (desempaquetar). Esto es interesante porque gracias a las tuplas, las funciones Python pueden devolver varios valores:
In [52]:
a, b = t2
a
Out[52]:
In [53]:
x = ["hi", 3, 1j]
x[1] = "other"
x
Out[53]:
In [54]:
x.append(1000.)
x
Out[54]:
In [55]:
sizes = {"big":100, "medium":50, "small":10, 3: 10}
sizes["big"]
Out[55]:
Los diccionares también son mutables e iterables (por claves), pero no permiten hacer slicing:
In [56]:
for key in sizes:
print(key)
In [57]:
sizes["big"] = 200
sizes
Out[57]:
In [58]:
s = set()
s.add("letter")
s.add(4.0)
s
Out[58]:
El conjunto soporta las típicas operaciones algebráicas como unión, intersección, diferencia, etc.
In [59]:
set([1, 2]).union(set([2, 3]))
Out[59]:
In [60]:
set([1, 2]).intersection(set([2, 3]))
Out[60]:
In [61]:
set([1, 2]).difference(set([2, 3]))
Out[61]: